#ifndef __MESICACHE_H__
#define __MESICACHE_H__

#include "CPU.h"
#include "base/Entity.h"
#include "base/EvictRequest.h"
#include "base/Packet.h"
#include "base/RawFlushRequest.h"
#include "base/SnoopRequest.h"
#include "mem/Cache.h"
#include "mem/InvalidateRequest.h"
#include "scc/MatchInfo.h"
#include "scc/MESIFlags.h"

/// A writeback cache with MESI coherence
class MESICache : public Cache {
  public:
    NEW_DELETE_OPERATORS_H(MESICache,Cache);

    MESICache (const char* name,
               uint size,
               uint block_size,
               uint assoc,
               uint vcsize,
               uint delay,
               uint mshrs,
               uint snoopDelay,
               LineFlags* protoFlags,
               Counter* statAccesses,
               Counter* statHits,
               Counter* statMisses,
               Bucket* _stallBkt,
               Bucket* _unavailBkt);
    virtual ~MESICache ();

    //    std::map<VA, std::pair<uint,bool> > llsc;
    VA llsc;
    virtual void tick ();

    virtual void hookLoadRefill (LoadRequest* lr, MSHR* mshr);
    virtual void hookPreRawFlush (RawFlushRequest* rfr);
    virtual void hookRawFlush (RawFlushRequest* rfr);
    virtual void hookVisitRawFlush (RawFlushRequest* rfr);
    virtual LoadRequest* makeRefillRequest (DataRequest* dr);

    virtual bool stalled (Packet* r);
    
  public:  double Ocounter;

  protected:

    uint stallBySnoop;
    uint snoopDelay;
    // snoopRequests keeps the snoop requests that've arrived to this cache but not 
    // processed yet.
    List<PacketDelay*>* snoopRequests;  

    virtual Result handle_SnoopRequest(Packet* r);
    void handle_SnoopRequest_ib(SnoopRequest * snr, MatchInfo * match);
    void handle_SnoopRequest_ch(SnoopRequest * snr, MatchInfo * match);
    void handle_SnoopRequest_mshr(SnoopRequest * snr, MatchInfo * match);
    void handle_SnoopRequest_ob(SnoopRequest * snr, MatchInfo * match);
    void handle_SnoopRequest_om(SnoopRequest * snr, MatchInfo * match);

    virtual Result handle_SnoopDelay (Packet* r);
    virtual Result handle_RawMemoryRequest (Packet* r);

    virtual Result handleAccess (DataRequest* dr, List<CacheEntry*>* entries);
    virtual Result handleStoreConditional (DataRequest* dr,  List<CacheEntry*>* list);
    bool isStoreConditional (DataRequest* dr);
    bool isLoadLock (DataRequest* dr);
    virtual void updateSnoopRequest (SnoopRequest* snr,
                                     void* data,
                                     uint dataSize,
                                     bool dirty = true);
                                 
    bool isL1 ();
    void sendAck (SnoopResponse* snrs);
    void cancelIncomingRequest (DataRequest* bdr);   

    void clearMatches (List<MatchInfo*>*);
    void removeEntry (MatchInfo * match);

    virtual void findMatches (DataRequest* dr, List<MatchInfo*>* matches, Request*);

    bool isTherePendingSnoopRequest (VA addr); 
    bool findMatchInOutputBuffer (VA addr, List<MatchInfo*>* matches, DataRequest*, Request*);
    bool findMatchInMSHR (VA addr, List<MatchInfo*>* matches, DataRequest*, Request*);
    bool findMatchInCacheHash (VA addr, List<MatchInfo*>* matches, DataRequest*, Request*);
    bool findMatchInInputBuffers (VA addr, List<MatchInfo*>* matches, DataRequest*, Request*);
};

#endif // __MESICACHE_H__
